package com.myrpc.consumer.rpc.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.myrpc.common.sessionchannel.Session;
import com.myrpc.common.vo.Request;
import com.myrpc.common.vo.Response;
import com.myrpc.consumer.discovery.zk.LoadBalanceChannelSession;

import lombok.extern.slf4j.Slf4j;

/**
 * Created by MACHENIKE on 2018-12-03.
 * java动态代理机制中有两个重要的类和接口InvocationHandler（接口）和Proxy（类）
 * 
 */
@Component
@Slf4j
public class RpcFactory<T> implements InvocationHandler {

	@Autowired
	LoadBalanceChannelSession loadBalanceChannelSession;

	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Request request = new Request();
		request.setClassName(method.getDeclaringClass().getName());
		// Session session = SessionMap.getSession(request.getClassName());
		Session session = loadBalanceChannelSession.chooseChannel(request.getClassName());

		request.setMethodName(method.getName());
		request.setParameters(args);
		request.setParameterTypes(method.getParameterTypes());
		request.setId(System.currentTimeMillis() + "");
		request.setServiceId(session.getObj() + "");

		// "className":"com.myrpc.user.face.InfoUserRemoteService",
		// "methodName":"getInfoUserById",
		log.info(JSON.toJSONString(request, true));
		Object result = session.clientSend(request);
		// session.writeAndFlush(JSON.toJSONString(request));
		log.info("result:{}", JSON.toJSONString("", true));

		Class<?> returnType = method.getReturnType();
		Response response = JSON.parseObject(JSON.toJSONString(result), Response.class);
		if (response.getCode() == 1) {
			throw new Exception(response.getError_msg());
		}
		if (returnType.isPrimitive() || String.class.isAssignableFrom(returnType)) {
			return response.getData();
		} else if (Collection.class.isAssignableFrom(returnType)) {
			return JSONArray.parseArray(response.getData().toString(), Object.class);
		} else if (Map.class.isAssignableFrom(returnType)) {
			return JSON.parseObject(response.getData().toString(), Map.class);
		} else {
			Object data = response.getData();
			return JSONObject.parseObject(data.toString(), returnType);
		}
	}
}
